<template>
  <div>
    <el-form :model="genForm" ref="genForm" :inline="true" label-width="68px" :rules="genRules">
      <el-form-item label="表名称" prop="tableName">
        <el-input v-model="genForm.tableName" placeholder="请输入表名称" clearable size="small" />
      </el-form-item>
      <el-form-item label="字段前缀" prop="colPrefix">
        <el-input v-model="genForm.colPrefix" placeholder="请输入字段前缀" clearable size="small" />
      </el-form-item>
      <el-form-item label="表描述" prop="tableDesc">
        <el-input v-model="genForm.tableDesc" placeholder="请输入表描述" clearable size="small" />
      </el-form-item>
    </el-form>
    <el-row>
      <el-col :span="11">
        <el-card class="box-card">
          <div slot="header" class="clearfix">
            <span>JSON</span>
            <el-button style="float: right; padding: 3px 0" type="text" @click="formatJSON">格式化</el-button>
          </div>
          <div class="text item">
            <el-input v-model="genForm.json" type="textarea" resize="none" :autosize="{minRows: 20, maxRows: 20}" />
          </div>
        </el-card>
      </el-col>
      <el-col :span="12" :offset="1">
        <el-card class="box-card">
          <div slot="header" class="clearfix">
            <span>注释（格式为<span style="color: #e65d6e">field comment type</span>，间隔为一个制表符\t）</span>
          </div>
          <div class="text item">
            <el-input v-model="genForm.comment" type="textarea" resize="none" :autosize="{minRows: 20, maxRows: 20}" />
          </div>
        </el-card>
      </el-col>
    </el-row>
    <div style="height: 36px; width: 100%; margin-top: 10px; overflow: hidden">
      <el-button style="float: right; margin-left: 10px" type="primary" plain @click="genConfig">{{ isGen ? '重新生成' : ' 生 成 ' }}</el-button>
      <el-button v-if="isGen" style="float: right" type="success" plain @click="openGenConfig = true">继续配置</el-button>
    </div>
    <el-dialog title="生成配置" :visible.sync="openGenConfig" width="1200px" append-to-body :close-on-click-modal="false">
      <el-table ref="dragTable" :data="genForm.columns" row-key="columnName" :max-height="400">
        <el-table-column label="序号" type="index" class-name="allowDrag" />
        <el-table-column label="字段列名" prop="columnName" :show-overflow-tooltip="true" />
        <el-table-column label="字段描述">
          <template slot-scope="scope">
            <el-input v-model="scope.row.comment"></el-input>
          </template>
        </el-table-column>
        <el-table-column label="物理类型">
          <template slot-scope="scope">
            <el-input v-model="scope.row.type"></el-input>
          </template>
        </el-table-column>
        <el-table-column label="主键" width="60px">
          <template slot-scope="scope">
            <el-checkbox v-model="scope.row.primaryKey"></el-checkbox>
          </template>
        </el-table-column>
        <el-table-column label="自增" width="60px">
          <template slot-scope="scope">
            <el-checkbox v-model="scope.row.autoIncrement"></el-checkbox>
          </template>
        </el-table-column>
        <el-table-column label="必填" width="60px">
          <template slot-scope="scope">
            <el-checkbox v-model="scope.row.notNull"></el-checkbox>
          </template>
        </el-table-column>
        <el-table-column label="包含默认值" width="120px">
          <template slot-scope="scope">
            <el-checkbox true-label="1" v-model="scope.row.hasDefaultValue" @change="v => (v ? undefined : (scope.row.defaultValue = undefined))"></el-checkbox>
          </template>
        </el-table-column>
        <el-table-column label="默认值">
          <template slot-scope="scope">
            <el-input :disabled="!scope.row.hasDefaultValue" v-model="scope.row.defaultValue"></el-input>
          </template>
        </el-table-column>
      </el-table>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="genSql">生成SQL</el-button>
      </div>
    </el-dialog>
    <el-dialog title="生成SQL" :visible.sync="openSql" width="800px" append-to-body :close-on-click-modal="false">
      <div style="white-space: pre">
        {{ genForm.sql }}
      </div>
    </el-dialog>
  </div>
</template>

<script>
import {humpToUnderline} from '@/utils/caseConvertor'
import {listReverseGenTableColumnMap} from '@/api/generator/ReverseGenTableColumnMap'

export default {
  name: 'ReverseGenTable',
  data() {
    return {
      genForm: {
        // 表名称
        tableName: '',
        // 字段前缀
        colPrefix: '',
        // 表描述
        tableDesc: '',
        // JSON内容
        json: '{}',
        // 注释
        comment: '',
        // 字段集合
        columns: [],
        // sql语句
        sql: ''
      },
      // 是否打开生成配置
      openGenConfig: false,
      // 反向生成表字段映射
      reverseGenTableColumnMapDataList: [],
      // 表单校验
      genRules: {
        tableName: [{required: true, message: '表名称不能为空', trigger: 'blur'}],
        tableDesc: [{required: true, message: '表描述不能为空', trigger: 'blur'}]
      },
      // 已有生成好的配置
      isGen: false,
      // 显示SQL语句
      openSql: false
    }
  },
  created() {
    this.loading = true
    listReverseGenTableColumnMap().then(res => {
      this.reverseGenTableColumnMapDataList = res.rows
      this.loading = false
    })
  },
  methods: {
    /**
     * 格式化JSON内容
     */
    formatJSON() {
      const json = this.convertValidJSON(this.genForm.json)
      if (!json) {
        return
      }
      this.genForm.json = JSON.stringify(json, null, 4)
    },
    /**
     * 校验JSON合法性并返回JSON对象
     * @param jsonText JSON文本
     */
    convertValidJSON(jsonText) {
      let json = {}
      try {
        json = JSON.parse(jsonText)
      } catch (ex) {
        console.error(ex)
        this.msgError('JSON格式错误')
        return false
      }
      return json
    },
    /**
     * 校验注释合法性
     * @param commentText 注释文本
     */
    validateComment(commentText) {
      return /^[\w]*[\t].*$|^[\w]*[\t].*[\t][\w\s]*$/.test(commentText)
    },
    /**
     * 生成配置信息
     */
    genConfig() {
      this.$refs['genForm'].validate(valid => {
        if (valid) {
          const json = this.convertValidJSON(this.genForm.json)
          if (!json) {
            return
          }
          const commentLines = this.genForm.comment.split('\n')
          const commentMap = {}
          for (let i = 0; i < commentLines.length; i++) {
            const c = commentLines[i]
            if (c && c.trim() && !this.validateComment(c)) {
              this.msgError('注释格式错误')
              return
            }
            const carr = c.split('\t')
            const key = carr[0]
            commentMap[key] = {
              commentText: '',
              type: undefined
            }
            commentMap[key].commentText = carr[1]
            commentMap[key].type = carr[2]
          }
          let colPrefix = this.genForm.colPrefix
          if (colPrefix && colPrefix.trim() && !colPrefix.endsWith('_')) {
            colPrefix += '_'
          }
          // 清空原有字段
          this.genForm.columns = []
          const keys = Object.keys(json)
          if (!keys.length) {
            this.msgError('没有数据')
            return
          }
          keys.forEach(k => {
            const column = {
              // 字段名称
              columnName: colPrefix + humpToUnderline(k),
              // 数据类型
              type: undefined,
              // 是否必填
              notNull: false,
              // 是否为主键
              primaryKey: false,
              // 包含默认值
              hasDefaultValue: false,
              // 默认值
              defaultValue: null,
              // 自增长
              autoIncrement: false
            }
            this.genForm.columns.push(column)
            let comment = commentMap[k]
            if (comment) {
              column.comment = comment.commentText
            }
            let type
            if (comment && comment.type) {
              type = comment.type
            } else {
              type = typeof json[k]
            }
            const map = this.reverseGenTableColumnMapDataList.find(m => type.toLowerCase() === m.mapType.toLowerCase())
            column.type = map ? map.mapTableColumnType : 'varchar(64)'
          })
          this.openGenConfig = true
          this.isGen = true
        }
      })
    },
    genSql() {
      let columnSqls = []
      this.genForm.columns.forEach(c => {
        columnSqls.push(
          `\t${c.columnName}\t${c.type}${c.notNull ? '\tnot null' : ''}${c.autoIncrement ? '\tauto_increment' : ''}${
            c.hasDefaultValue && (typeof c.defaultValue === 'number' || typeof c.defaultValue === 'string') ? "\tdefault '" + c.defaultValue + "'" : ''
          }${c.comment ? "\tcomment '" + c.comment + "'" : ''}`
        )
      })
      let columnSql = columnSqls.join(',\n')
      const primaryKeys = this.genForm.columns.filter(c => c.primaryKey)
      if (primaryKeys.length) {
        columnSql += `,
          primary key (${primaryKeys.join(',')})
        `
      }
      this.genForm.sql = `
drop table if exists ${this.genForm.tableName};
create table ${this.genForm.tableName} (
${columnSql}
        ) engine=innodb auto_increment=100 comment = '${this.genForm.tableDesc}';
      `
      this.openSql = true
    }
  }
}
</script>

<style scoped lang="scss"></style>
